package org.luxor.commons.core.utils.verify;

import org.apache.commons.lang.StringUtils;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 身份证号码校验工具类
 *
 * @author HabenChan @date 2018/5/31.
 */
public class IDCardUtils {

    // 老身份证15位
    public static final int IDENTITYCODE_OLD = 15;
    // 新身份证18位
    public static final int IDENTITYCODE_NEW = 18;

    private static int[] WI = new int[17];
    public static final Pattern PT = Pattern.compile("(^\\d{15}$)|(^\\d{18}$)|(^\\d{17}(\\d|X)$)");

    /**
     * 判断身份证号码是否正确。
     *
     * @param code 身份证号码。
     * @return 如果身份证号码正确，则返回true，否则返回false。
     */
    @SuppressWarnings("All")
    public static boolean isIDcard(String code) {
        if (StringUtils.isEmpty(code)) {
            return false;
        }
        String birthDay;
        code = code.trim();

        // 长度只有15和18两种情况
        if ((code.length() != IDENTITYCODE_OLD)
                && (code.length() != IDENTITYCODE_NEW)) {
            return false;
        }

        // 身份证号码必须为数字(18位的新身份证最后一位可以是x)
        Matcher mt = PT.matcher(code);
        if (!mt.find()) {
            return false;
        }

        // 验证生日
        if (code.length() == IDENTITYCODE_OLD) {
            birthDay = "19" + code.substring(6, 12);
        } else {
            birthDay = code.substring(6, 14);
        }
        if (!isRightDate(birthDay, "yyyyMMdd")) {
            return false;
        }

        // 最后一位校验码验证
        if (code.length() == IDENTITYCODE_NEW) {
            String lastNum = getCheckFlag(code.substring(0, IDENTITYCODE_NEW - 1));
            // check last digit
            if (!("" + code.charAt(IDENTITYCODE_NEW - 1)).toUpperCase().equals(
                    lastNum)) {
                return false;
            }
        }
        return true;
    }

    private static boolean isRightDate(String birthDay, String format) {
        try {
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(format);
            LocalDate iDCardDate = LocalDate.parse(birthDay, dateTimeFormatter);
            if (iDCardDate.getYear() < 1900) {
                return false;
            }
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    /**
     * 获取新身份证的最后一位:检验位
     *
     * @param code 18位身份证的前17位
     * @return 新身份证的最后一位
     */
    private static String getCheckFlag(String code) {
        int[] varArray = new int[code.length()];
        String lastNum;
        int numSum = 0;
        // 初始化位权值
        setWiBuffer();
        for (int i = 0; i < code.length(); i++) {
            varArray[i] = Integer.valueOf("" + code.charAt(i));
            varArray[i] = varArray[i] * WI[i];
            numSum = numSum + varArray[i];
        }
        int checkDigit = 12 - numSum % 11;
        switch (checkDigit) {
            case 10:
                lastNum = "X";
                break;
            case 11:
                lastNum = "0";
                break;
            case 12:
                lastNum = "1";
                break;
            default:
                lastNum = String.valueOf(checkDigit);
        }
        return lastNum;
    }

    /**
     * 初始化位权值
     */
    private static void setWiBuffer() {
        for (int i = 0; i < WI.length; i++) {
            int k = (int) Math.pow(2, (WI.length - i));
            WI[i] = k % 11;
        }
    }

    /**
     * 将15位身份证号码升级为18位身份证号码
     *
     * @param code 15位身份证号码
     * @return 18位身份证号码
     */
    public static String update2eighteen(String code) {
        if (StringUtils.isEmpty(code)) {
            return "";
        }
        code = code.trim();
        if (code.length() != IDENTITYCODE_OLD || !isIDcard(code)) {
            return "";
        }
        code = code + getCheckFlag(code);
        return code;
    }

}
